package com.yky.filter;

import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.sign.SaSignUtil;
import com.alibaba.fastjson.JSON;
import com.yky.utils.SmUtils;
import com.yky.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

public class RequestWrapper extends HttpServletRequestWrapper {
    private static final Logger log = LoggerFactory.getLogger(RequestWrapper.class);
    private final String body;
    private static final Integer MINIMUM = 0;
    private static final Integer MAXIMUM = 16;
    private static Map<String, String> params = new HashMap<>();

    public RequestWrapper(HttpServletRequest request,String token,Boolean decrypt) {
        super(request);
        if ("GET".equals(request.getMethod())){
            String data = request.getParameter("data");
            if (StringUtils.isNotBlank(data)){
                data = decrypt(data, token, decrypt);
                params = getMapData(data);
            }
            body = "";
            return;
        }
        String resultstr = this.readInputStream(request);
        resultstr = decrypt(resultstr, token, decrypt);
        /*String contentType = request.getContentType();
        if (StringUtils.startsWithIgnoreCase(contentType, MediaType.APPLICATION_JSON_VALUE) && StringUtils.isNotBlank(resultstr)){
            Map<String, String> map = JSON.parseObject(resultstr, Map.class);
            SaManager.getSaSignTemplate().checkParamMap(map);
            resultstr = map.get("data");
        }*/
        body = resultstr;
    }

    /**
     * 解密
     * @param resultstr
     * @param token
     * @param decrypt
     * @return
     */
    private String decrypt(String resultstr, String token, boolean decrypt){
        try {
            if (StringUtils.isNotBlank(resultstr) && StringUtils.isNotBlank(token) &&
                    !StringUtils.equals("undefined", token) && decrypt) {
                //截取前16位作为加密秘钥
                String key = token.substring(MINIMUM, MAXIMUM);
                //SM4解密
                resultstr = SmUtils.decryptEcb(key, resultstr);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultstr;
    }

    /**
     * 获取get请求原始参数
     * @param qString
     * @return
     */
    private Map<String, String> getMapData(String qString) {
        String[] strs = qString.split("&");
        Map<String, String> dataMap = new HashMap<>(16);
        for (int i = 0; i < strs.length; i++) {
            String[] str = strs[i].split("=");
            dataMap.put(str[0], str[1]);
        }
        return dataMap;
    }

    private String readInputStream(HttpServletRequest request) {
        StringBuilder stringBuilder = new StringBuilder();
        BufferedReader bufferedReader = null;
        InputStream inputStream = null;
        try {
            inputStream = request.getInputStream();
            if (inputStream != null) {
                bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
                char[] charBuffer = new char[128];
                int bytesRead = -1;
                while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                    stringBuilder.append(charBuffer, 0, bytesRead);
                }
            } else {
                stringBuilder.append("");
            }
        } catch (IOException ex) {
            log.error("", ex);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return stringBuilder.toString();
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
        ServletInputStream servletInputStream = new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }
            @Override
            public boolean isReady() {
                return false;
            }
            @Override
            public void setReadListener(ReadListener readListener) {
            }
            @Override
            public int read() throws IOException {
                return byteArrayInputStream.read();
            }
        };
        return servletInputStream;

    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }

    public String getBody() {
        return this.body;
    }

    @Override
    public String[] getParameterValues(String name) {
        if (params.containsKey(name)){
            return new String[] {params.get(name)};
        }else{
            return super.getParameterValues(name);
        }
    }

    @Override
    public String getParameter(String name) {
        if (params.containsKey(name)){
            return params.get(name);
        }else{
            return super.getParameter(name);
        }
    }
}
